package com.rustyard.ddnetranks;

import androidx.appcompat.app.AppCompatActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

import org.jsoup.HttpStatusException;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

import java.io.IOException;
import java.lang.ref.WeakReference;
import java.net.SocketTimeoutException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    Button button;
    EditText editText;
    TextView textView;

    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.buttonSearch) {
            String playerID = editText.getText().toString();

            // For characters that is not a letter, not a digit, or is not in ASCII range:
            // get UTF-8 code as decimal number then add two '-', like this: -24352- for 张
            // and then replace that character.
            if (!playerID.isEmpty()) {
                StringBuilder sbPlayerID = new StringBuilder();
                int codePointCount = playerID.codePointCount(0,playerID.length());
                for (int i = 0; i < codePointCount; i++) {
                    // get the actual code point for every UTF characters one by one
                    int index = playerID.offsetByCodePoints(0,i);
                    int codePoint = playerID.codePointAt(index);
                    // check if this character needs to be replaced
                    if (!Character.isSupplementaryCodePoint(codePoint)) {
                        if (Character.isLetterOrDigit(codePoint) && codePoint < 256)
                            sbPlayerID.append((char) codePoint);
                        else
                            sbPlayerID.append("-").append(codePoint).append("-");
                    } else {
                        sbPlayerID.append("-").append(codePoint).append("-");
                    }
                }
                new ParseTask(this).execute(sbPlayerID.toString());
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.buttonSearch);
        textView = findViewById(R.id.textScore);
        editText = findViewById(R.id.editTextPlayerID);
        button.setOnClickListener(this);
    }

    private static class ParseTask extends AsyncTask<String, Integer, Spanned> {
        protected WeakReference<MainActivity> activityWeakReference;

        public ParseTask(MainActivity context) {
            super();
            this.activityWeakReference = new WeakReference<>(context);
        }

        @Override
        protected void onPreExecute() {
            MainActivity mainActivity = activityWeakReference.get();
            if (mainActivity == null || mainActivity.isFinishing()) return;

            TextView text = mainActivity.findViewById(R.id.textScore);
            text.setText(R.string.stringWaitForResult);
        }

        @Override
        protected Spanned doInBackground(String... params) {
            Document ddnetPage = null;
            String result;
            Elements ranking;
            Elements lastFinish;
            Elements firstFinish;
            Elements monthlyPoints;
            Elements weeklyPoints;
            Elements novicePoints;
            Elements moderatePoints;
            Elements brutalPoints;
            Elements insanePoints;
            Elements dummyPoints;
            Elements ddmaxPoints;
            Elements soloPoints;
            Elements oldschoolPoints;
            Elements racePoints;


            try {
                ddnetPage = Jsoup.connect("https://ddnet.tw/players/" + params[0] + "/").get();
            } catch (HttpStatusException httpStatusException) {
                return Html.fromHtml("<font color=\"#ff0000\">无结果</font>：注意玩家名是否输入正确（区分大小写）");
            } catch (SocketTimeoutException timeoutException) {
                return Html.fromHtml("<font color=\"#ff0000\">请求超时</font>");
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (ddnetPage != null) {
                String pattern1 = "(\\d+)\\D+(\\d+)\\D+";
                // pattern used for "<rank>. with <points> points"
                Pattern patternRankAndPoints = Pattern.compile(pattern1);

                // get ranks and points on the screen
                ranking = ddnetPage.select(".ladder:nth-child(1) .pers-result");
                Matcher matcherRankAndPoints = patternRankAndPoints.matcher(ranking.text());
                if (matcherRankAndPoints.find()) {
                    result = "<b>全球排名: </b>" + matcherRankAndPoints.group(1);
                    result += "<br><b>总点数: </b>" + matcherRankAndPoints.group(2);
                } else { result = "<font color=\"#ff0000\">正则表达式匹配出错:total</font>"; }

                result += "<br>"; // add a new line, make it look better

                // get the first finish record
                firstFinish = ddnetPage.select(".personal-result");
                result += "<br><b>第一次过关的图: </b><br>" + firstFinish.text();

                // get the newest finish record
                lastFinish = ddnetPage.select(".block7+ .ladder tr:nth-child(1) td");
                result += "<br><b>最近完成的图(UTC+02:00): </b><br>"+ lastFinish.text();

                // get the monthly points ranking
                monthlyPoints = ddnetPage.select("#global br+ .ladder .pers-result");
                Matcher matcherMonthlyPoints = patternRankAndPoints.matcher(monthlyPoints.text());
                if (matcherMonthlyPoints.find()) {
                    result += "<br><b>本月获得点数: </b>" + matcherMonthlyPoints.group(2)
                            + " <b>排名: </b>" + matcherMonthlyPoints.group(1);
                } else {
                    if (monthlyPoints.text().equals("Unranked")) {
                        result += "<br><b>本月获得点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:monthly</font>";
                    }
                }

                // get the weekly points ranking
                weeklyPoints = ddnetPage.select("#global .ladder:nth-child(6) .pers-result");
                Matcher matcherWeeklyPoints = patternRankAndPoints.matcher(weeklyPoints.text());
                if (matcherWeeklyPoints.find()) {
                    result += "<br><b>本周获得点数: </b>" + matcherWeeklyPoints.group(2)
                            + " <b>排名: </b>" + matcherWeeklyPoints.group(1);
                } else {
                    if (weeklyPoints.text().equals("Unranked")) {
                        result += "<br><b>本周获得点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:weekly</font>";
                    }
                }

                result += "<br>";

                // TODO: add a online status (get information from status.tw)
                // NOTE: status.tw is slow to connect from China so this feature may be gave up.

                // TODO: add a map finish record searcher

                // TODO: add a country display
                // TODO: show the country in picture


                // Novice maps "rank and points" display
                novicePoints = ddnetPage.select("#Novice br+ .ladder .pers-result");
                Matcher matcherNovicePoints = patternRankAndPoints.matcher(novicePoints.text());
                if (matcherNovicePoints.find()) {
                    result += "<br><b>Novice新手图总点数: </b>" + matcherNovicePoints.group(2)
                            + " <b>排名: </b>" + matcherNovicePoints.group(1);
                } else {
                    if (novicePoints.text().equals("Unranked")) {
                        result += "<br><b>Novice新手图总点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:novice</font>";
                    }
                }

                // Moderate maps "rank and points" display
                moderatePoints = ddnetPage.select("#Moderate br+ .ladder .pers-result");
                Matcher matcherModeratePoints = patternRankAndPoints.matcher(moderatePoints.text());
                if (matcherModeratePoints.find()) {
                    result += "<br><b>Moderate中阶图总点数: </b>" + matcherModeratePoints.group(2)
                            + " <b>排名: </b>" + matcherModeratePoints.group(1);
                } else {
                    if (moderatePoints.text().equals("Unranked")) {
                        result += "<br><b>Moderate中阶图总点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:moderate</font>";
                    }
                }

                // Brutal maps "rank and points" display
                brutalPoints = ddnetPage.select("#Brutal br+ .ladder .pers-result");
                Matcher matcherBrutalPoints = patternRankAndPoints.matcher(brutalPoints.text());
                if (matcherBrutalPoints.find()) {
                    result += "<br><b>Brutal高阶图总点数: </b>" + matcherBrutalPoints.group(2)
                            + " <b>排名: </b>" + matcherBrutalPoints.group(1);
                } else {
                    if (brutalPoints.text().equals("Unranked")) {
                        result += "<br><b>Brutal高阶图总点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:brutal</font>";
                    }
                }

                // Insane maps "rank and points" display
                insanePoints = ddnetPage.select("#Insane br+ .ladder .pers-result");
                Matcher matcherInsanePoints = patternRankAndPoints.matcher(insanePoints.text());
                if (matcherInsanePoints.find()) {
                    result += "<br><b>Insane疯狂图总点数: </b>" + matcherInsanePoints.group(2)
                            + " <b>排名: </b>" + matcherInsanePoints.group(1);
                } else {
                    if (insanePoints.text().equals("Unranked")) {
                        result += "<br><b>Insane疯狂图总点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:insane</font>";
                    }
                }

                // Dummy maps "rank and points" display
                dummyPoints = ddnetPage.select("#Dummy br+ .ladder .pers-result");
                Matcher matcherDummyPoints = patternRankAndPoints.matcher(dummyPoints.text());
                if (matcherDummyPoints.find()) {
                    result += "<br><b>Dummy分身图总点数: </b>" + matcherDummyPoints.group(2)
                            + " <b>排名: </b>" + matcherDummyPoints.group(1);
                } else {
                    if (dummyPoints.text().equals("Unranked")) {
                        result += "<br><b>Dummy分身图总点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:dummy</font>";
                    }
                }

                // DDmaX maps "rank and points" display
                ddmaxPoints = ddnetPage.select("#DDmaX br+ .ladder .pers-result");
                Matcher matcherDDmaXPoints = patternRankAndPoints.matcher(ddmaxPoints.text());
                if (matcherDDmaXPoints.find()) {
                    result += "<br><b>DDmaX古典图总点数: </b>" + matcherDDmaXPoints.group(2)
                            + " <b>排名: </b>" + matcherDDmaXPoints.group(1);
                } else {
                    if (ddmaxPoints.text().equals("Unranked")) {
                        result += "<br><b>DDmaX古典图总点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:ddmax</font>";
                    }
                }

                // Oldschool maps "rank and points" display
                oldschoolPoints = ddnetPage.select("#Oldschool br+ .ladder .pers-result");
                Matcher matcherOldschoolPoints = patternRankAndPoints.matcher(oldschoolPoints.text());
                if (matcherOldschoolPoints.find()) {
                    result += "<br><b>Oldschool复古图总点数: </b>" + matcherOldschoolPoints.group(2)
                            + " <b>排名: </b>" + matcherOldschoolPoints.group(1);
                } else {
                    if (oldschoolPoints.text().equals("Unranked")) {
                        result += "<br><b>Oldschool复古图总点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:oldschool</font>";
                    }
                }

                // Solo maps "rank and points" display
                soloPoints = ddnetPage.select("#Solo br+ .ladder .pers-result");
                Matcher matcherSoloPoints = patternRankAndPoints.matcher(soloPoints.text());
                if (matcherSoloPoints.find()) {
                    result += "<br><b>Solo单人图总点数: </b>" + matcherSoloPoints.group(2)
                            + " <b>排名: </b>" + matcherSoloPoints.group(1);
                } else {
                    if (soloPoints.text().equals("Unranked")) {
                        result += "<br><b>Solo单人图总点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:solo</font>";
                    }
                }

                // Race maps "rank and points" display
                racePoints = ddnetPage.select("#Race br+ .ladder .pers-result");
                Matcher matcherRacePoints = patternRankAndPoints.matcher(racePoints.text());
                if (matcherRacePoints.find()) {
                    result += "<br><b>Race竞速图总点数: </b>" + matcherRacePoints.group(2)
                            + " <b>排名: </b>" + matcherRacePoints.group(1);
                } else {
                    if (racePoints.text().equals("Unranked")) {
                        result += "<br><b>Race竞速图总点数: </b>0";
                    } else {
                        result += "<font color=\"#ff0000\">正则表达式匹配出错:race</font>";
                    }
                }

                // TODO: add a "most recommended map to finish"



                return Html.fromHtml(result);
            }
            else
                return Html.fromHtml("<font color=\"#ff0000\">无结果</font>");
        }

        @Override
        protected void onPostExecute(Spanned result) {
            MainActivity mainActivity = activityWeakReference.get();
            if (mainActivity == null || mainActivity.isFinishing()) return;

            TextView text = mainActivity.findViewById(R.id.textScore);
            text.setText(result);
        }
    }

}